package com.bianmaba.test.repository.support;


import com.bianmaba.commons.bean.result.QueryResult;
import com.bianmaba.commons.data.jpa.domain.request.Condition;
import com.bianmaba.commons.data.jpa.domain.request.PageableCondition;
import com.bianmaba.test.TestApplication;
import org.example.test.bean.User;
import org.example.test.bean.UserDetail;
import org.example.test.respoistory.UserRepository;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {TestApplication.class})
@Transactional()
public class BianmabaRepositoryTester {
    @Autowired
    private UserRepository repository;

    public BianmabaRepositoryTester() {
        System.out.println(repository);
    }

    private User entity = null;

    private List<User> entities = new ArrayList<>();

    @Before
    public void before() {
        entity = new User();
        entity.setName("test");
        repository.save(entity);

        for (int i = 0; i < 5; i++) {
            User user = new User("test" + i);
            user.setDetail(new UserDetail(i + "80477286@163.com"));
            user.setMoney(BigDecimal.valueOf(1.0 * i));
            user.setAge(BigInteger.valueOf(i));
            entities.add(user);
        }

        repository.saveAll(entities);
        repository.flush();
        repository.clear();
    }

    @Test
    public void save() {
        Assert.assertNotNull(repository);
        User entity = new User();
        entity.setName("test1");
        User newEntity = repository.save(entity);
        repository.flush();
        repository.clear();
        newEntity = repository.findById(newEntity.getId()).get();
        Assert.assertNotNull(newEntity);
    }

    @Test
    public void findById() {
        User te = repository.findById(entity.getId()).get();
        Assert.assertNotNull(te);
    }

    @Test
    public void delete() {
        repository.delete(entity);
    }

    @Test
    public void deleteAll() {
        repository.deleteAll();
    }

    @Test
    public void deleteList() {
        repository.deleteAll(entities);
    }

    @Test
    public void deleteAllInBatch() {
        repository.deleteAllInBatch();
    }

    @Test
    public void deleteInBatch() {
        repository.deleteInBatch(entities);
    }

    @Test
    public void deleteById() {
        repository.deleteById(entity.getId());
    }

    @Test
    public void count() {
        Condition condition = Condition.of("name", ":like:", "es");

        long count = repository.count(condition);
        Assert.assertEquals(count, 6);


        count = repository.count("name", "test1");
        Assert.assertEquals(count, 1);

        LinkedHashMap<String, Object> params = new LinkedHashMap<>(0);
        params.put("name", "test4");
        count = repository.count(params);
        Assert.assertEquals(count, 1);
    }

    @Test
    public void exists() {
        Condition condition = Condition.of("name", ":like:", "es");

        boolean exists = repository.exists(condition);
        Assert.assertTrue(exists);


        exists = repository.exists("name", "test5");
        Assert.assertFalse(exists);

        LinkedHashMap<String, Object> params = new LinkedHashMap<>(0);
        params.put("name", "test4");

        exists = repository.exists(params);
        Assert.assertTrue(exists);
    }

    //测试in查询
    @Test
    public void queryByOps() {
        //like比较查询，预期返回数据条数为1
        LinkedHashMap<String, Object> params = new LinkedHashMap<>(0);
        params.put("name_in", Arrays.asList(new String[]{"test1", "test2"}));
        List<User> list = repository.queryToList(params);
        Assert.assertEquals(list.size(), 2);

        params = new LinkedHashMap<>(0);
        params.put("name_in", new String[]{"test1", "test2"});
        list = repository.queryToList(params);
        Assert.assertEquals(list.size(), 2);


        params = new LinkedHashMap<>(0);
        params.put("money_eq", 1.0);
        list = repository.queryToList(params);
        Assert.assertEquals(list.size(), 1);

        params = new LinkedHashMap<>(0);
        params.put("age_eq", 1);
        list = repository.queryToList(params);
        Assert.assertEquals(list.size(), 1);


        params.clear();
        params.put("age_btw", new Integer[]{1, 2});
        list = repository.queryToList(params);
        Assert.assertEquals(list.size(), 2);
    }

    @Test
    public void findAll() {
        List<User> list = repository.findAll((Specification<User>) (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.like(root.get("name"), "%es%"));
        Assert.assertEquals(list.size(), 6);

        list = repository.findAll((Specification<User>) (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.like(root.join("detail").get("email"), "%286%"));
        Assert.assertEquals(list.size(), 5);
    }

    @Test
    public void querySingle() {
        //like比较查询，预期返回数据条数为1
        Condition condition = Condition.of("name", "eq", "test1");
        User user = repository.querySingle(condition);
        Assert.assertNotNull(user);


        //like比较查询，预期返回数据条数为1
        condition = Condition.of("detail.email", "eq", "180477286@163.com");
        user = repository.querySingle(condition);
        Assert.assertNotNull(user);


        //like比较查询，预期返回数据条数为1
        LinkedHashMap<String, Object> params = new LinkedHashMap<>(0);
        params.put("name_eq", "test1");
        user = repository.querySingle(params);
        Assert.assertNotNull(user);


        //like比较查询，预期返回数据条数为1
        params = new LinkedHashMap<>(0);
        params.put("detail.email", "180477286@163.com");
        user = repository.querySingle(params);
        Assert.assertNotNull(user);
    }

    @Test
    public void sortQueryToListUseLinkedHashMap() {
        //like比较查询，预期返回数据条数为1

        LinkedHashMap<String, Object> params = new LinkedHashMap<>(0);
        params.put("name_:like:", "es");
        Pageable pageable = PageRequest.of(0, 1, Sort.Direction.DESC, new String[]{"id"});

        List<User> list = repository.queryToList(params, pageable);
        Assert.assertEquals(list.size(), 1);
        Assert.assertEquals(list.get(0).getName(), "test4");
    }

    @Test
    public void queryToListUseLinkedHashMap() {
        //like比较查询，预期返回数据条数为1
        LinkedHashMap<String, Object> params = new LinkedHashMap<>(0);
        params.put("name_:like:", "test1");
        List<User> list = repository.queryToList(params);
        Assert.assertEquals(list.size(), 1);

        //like比较查询，预期返回数据条数为6
        params.clear();
        params.put("name_:like:", "es");
        list = repository.queryToList(params);
        Assert.assertEquals(list.size(), 6);

        params.clear();
        params.put("name_:like:", "es");
        Pageable pageable = PageRequest.of(0, 1);
        list = repository.queryToList(params, pageable);
        Assert.assertEquals(list.size(), 1);

        params.clear();
        params.put("name_:like:", "es");
        pageable = PageRequest.of(1, 4);

        list = repository.queryToList(params, pageable);
        Assert.assertEquals(list.size(), 2);

        list = repository.queryToList(params, true);
        Assert.assertEquals(list.size(), 6);


        list = repository.queryToList((LinkedHashMap<String, Object>) null);
        Assert.assertEquals(list.size(), 6);
    }


    @Test
    public void queryUseLinkedHashmap() {
        LinkedHashMap<String, Object> params = new LinkedHashMap<>(0);
        params.put("name_:like:", "es");
        Pageable pageable = PageRequest.of(0, 4);

        QueryResult<List<User>> result = repository.query(params, pageable);
        Assert.assertEquals(result.getTotalPage(), 2);
        Assert.assertEquals(result.getSize(), 4);
        Assert.assertEquals(result.getPage(), 0);
        Assert.assertEquals(result.getPageSize(), 4);

        pageable = PageRequest.of(1, 5);
        result = repository.query(params, pageable);
        Assert.assertEquals(result.getTotalPage(), 2);
        Assert.assertEquals(result.getSize(), 5);
        Assert.assertEquals(result.getPage(), 1);
        Assert.assertEquals(result.getPageSize(), 1);


        pageable = PageRequest.of(0, 7);
        result = repository.query(params, pageable);
        Assert.assertEquals(result.getTotalPage(), 1);
        Assert.assertEquals(result.getPageSize(), 6);


        pageable = PageRequest.of(1, 7);
        result = repository.query(params, pageable);
        Assert.assertEquals(result.getTotalPage(), 1);
        Assert.assertEquals(result.getPageSize(), 0);
    }

    @Test
    public void queryToList() {
        //like比较查询，预期返回数据条数为1
        Condition condition = Condition.of("name", ":like:", "test1");
        List<User> list = repository.queryToList(condition);
        Assert.assertEquals(list.size(), 1);

        //like比较查询，预期返回数据条数为6
        condition = Condition.of("name", ":like:", "es");
        list = repository.queryToList(condition);
        Assert.assertEquals(list.size(), 6);

        condition = Condition.ofOr().addOr("name", "eq", "test1")
                .addOr("detail.email", "eq", "280477286@163.com").
                        addOr(Condition.ofAnd().addAnd("detail.email", ":like:", "286").addAnd("detail.email", ":like:", "163"));
        list = repository.queryToList(condition);
        Assert.assertEquals(list.size(), 5);

        PageableCondition pageableCondition = PageableCondition.of("name", ":like:", "es", 0, 1);
        list = repository.queryToList(pageableCondition);
        Assert.assertEquals(list.size(), 1);


        pageableCondition = PageableCondition.of("name", ":like:", "es", 1, 4);
        list = repository.queryToList(pageableCondition);
        Assert.assertEquals(list.size(), 2);


        list = repository.queryToList((Condition) null);
        Assert.assertEquals(list.size(), 6);


        list = repository.queryToList("name", "test1");
        Assert.assertEquals(list.size(), 1);

        list = repository.queryToList("name", "test1", true);
        Assert.assertEquals(list.size(), 1);
    }

    @Test
    public void sortQueryToList() {
        //like比较查询，预期返回数据条数为1
        Condition condition = (Condition) Condition.of("name", ":like:", "es").addSort("id", "desc");
        List<User> list = repository.queryToList(condition);
        Assert.assertEquals(list.size(), 6);
        Assert.assertEquals(list.get(0).getName(), "test4");

        condition = (Condition) PageableCondition.of("name", ":like:", "es").addSort("id", "desc");
        list = repository.queryToList(condition);
        Assert.assertEquals(list.size(), 6);
        Assert.assertEquals(list.get(0).getName(), "test4");
    }

    @Test
    public void query() {
        PageableCondition pageableCondition = PageableCondition.of("name", ":like:", "es", 0, 4);
        QueryResult<List<User>> result = repository.query(pageableCondition);
        Assert.assertEquals(result.getTotalPage(), 2);
        Assert.assertEquals(result.getSize(), 4);
        Assert.assertEquals(result.getPage(), 0);
        Assert.assertEquals(result.getPageSize(), 4);


        pageableCondition = PageableCondition.of("name", ":like:", "es", 1, 5);
        result = repository.query(pageableCondition);
        Assert.assertEquals(result.getTotalPage(), 2);
        Assert.assertEquals(result.getSize(), 5);
        Assert.assertEquals(result.getPage(), 1);
        Assert.assertEquals(result.getPageSize(), 1);


        pageableCondition = PageableCondition.of("name", ":like:", "es", 0, 7);
        result = repository.query(pageableCondition);
        Assert.assertEquals(result.getTotalPage(), 1);
        Assert.assertEquals(result.getPageSize(), 6);


        pageableCondition = PageableCondition.of("name", ":like:", "es", 1, 7);
        result = repository.query(pageableCondition);
        Assert.assertEquals(result.getTotalPage(), 1);
        Assert.assertEquals(result.getPageSize(), 0);
    }

    @Test
    public void queryBySpec() {
        Specification<User> specification = new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                return null;
            }
        };
        Pageable pageable = PageRequest.of(0, 1);
        QueryResult result = this.repository.query(specification, pageable, null);
        Assert.assertEquals(result.getTotalPage(), 6);
        Assert.assertEquals(result.getPageSize(), 1);

    }
}
